#include "board.hpp"

namespace gomoku{

    board::board(int height, int width){
        _width = width;
        _height = height;
        int size=height*width;
        _points = new point_status[size];
        memset(_points,0,size*sizeof(point_status));
        _black_cnt=_white_cnt=_disabled_cnt=0;
    }

    board::board(int height, int width, point_status *raw_layout_array){
        _width = width;
        _height = height;
        int size=height*width;
        _points = new point_status[size];
        memcpy(_points,raw_layout_array,size*sizeof(point_status));
        _black_cnt=_white_cnt=_disabled_cnt=0;
        for (int i=0;i<size;++i){
            switch (_points[i]){
                case point_status::black:
                    ++_black_cnt;
                    break;
                case point_status::white:
                    ++_white_cnt;
                    break;
                case point_status::disabled:
                    ++_disabled_cnt;
                    break;
            }
        }
    }

    board::~board(){
        delete[] _points;
    }

    pattern::pattern(){}

    pattern::pattern(std::initializer_list<glob> _glob_list){
        for (auto i:_glob_list){
            glob_list.push_back(i);
        }
    }

    void board::place_black(point pos){
        if (pos.col>=0 && pos.col<_width && pos.row>=0 && pos.row<_height){ // 越界检查
            int index = pos.row*_width+pos.col;
            point_status pre_status = _points[index];
            _points[index] = point_status::black;
            // 更改内置计数器
            switch (pre_status){
                case point_status::white:
                    --_white_cnt;
                    break;
                case point_status::black:
                    --_black_cnt;
                    break;
                case point_status::disabled:
                    --_disabled_cnt;
                    break;
            }
            ++_black_cnt;
            // 更新改动记录
            _change_log.push_back(board_event{pos,point_status::black,pre_status});
            // 棋盘的变化会出发on_event()
            if (on_event){
                on_event(*this);
            }
        }
    }

    void board::place_white(point pos){
        if (pos.col>=0 && pos.col<_width && pos.row>=0 && pos.row<_height){ // 越界检查
            int index = pos.row*_width+pos.col;
            point_status pre_status = _points[index];
            _points[index] = point_status::white;
            // 更改内置计数器
            switch (pre_status){
                case point_status::white:
                    --_white_cnt;
                    break;
                case point_status::black:
                    --_black_cnt;
                    break;
                case point_status::disabled:
                    --_disabled_cnt;
                    break;
            }
            ++_white_cnt;
            // 更新改动记录
            _change_log.push_back(board_event{pos,point_status::white,pre_status});
            // 棋盘的变化会出发on_event()
            if (on_event){
                on_event(*this);
            }
        }
    }

    void board::clear_point(point pos){
        if (pos.col>=0 && pos.col<_width && pos.row>=0 && pos.row<_height){ // 越界检查
            int index = pos.row*_width+pos.col;
            point_status pre_status = _points[index];
            _points[index] = point_status::vacant;
            // 更改内置计数器
            switch (pre_status){
                case point_status::white:
                    --_white_cnt;
                    break;
                case point_status::black:
                    --_black_cnt;
                    break;
                case point_status::disabled:
                    --_disabled_cnt;
                    break;
            }
            // 更新改动记录
            _change_log.push_back(board_event{pos,point_status::vacant,pre_status});
            // 棋盘的变化会出发on_event()
            if (on_event){
                on_event(*this);
            }
        }
    }

    void board::disable_point(point pos){
        if (pos.col>=0 && pos.col<_width && pos.row>=0 && pos.row<_height){ // 越界检查
            int index = pos.row*_width+pos.col;
            point_status pre_status = _points[index];
            _points[index] = point_status::disabled;
            // 更改内置计数器
            switch (pre_status){
                case point_status::white:
                    --_white_cnt;
                    break;
                case point_status::black:
                    --_black_cnt;
                    break;
                case point_status::disabled:
                    --_disabled_cnt;
                    break;
            }
            ++_disabled_cnt;
            // 更新改动记录
            _change_log.push_back(board_event{pos,point_status::disabled,pre_status});
            // 棋盘的变化会出发on_event()
            if (on_event){
                on_event(*this);
            }
        }
    }

    point_status board::operator [](point pos) const{
        //  如果越界，则返回被禁用的状态作为哨兵
        if (pos.col<0 || pos.row<0 || pos.col>=_width || pos.row>=_height){
            return point_status::disabled;
        }else{
            return _points[pos.row*_width+pos.col];
        }
    }

    bool pattern::match(const board &Board, const point &pos) const{
        for (auto i:glob_list){
            if (i.positive){
                if (Board[pos+i.pos]!=i.status){
                    return false;
                }
            }else{
                if (Board[pos+i.pos]==i.status){
                    return false;
                }
            }
        }
        return true;
    }

    point pattern::find(const board &Board) const{
        for (int i=0;i<Board.height();++i){
            for (int j=0;j<Board.width();++j){
                if (match(Board,point{i,j})){
                    return point{i,j};
                }
            }
        }
        return point{-1,-1};
    }

}